;^Z80^
; modem control information
; Coleco 300 baud direct connect modem
; 4/5/84
;
; Data port = 05EH
; Control port = 05FH
;
; Useful equates
DATAP EQU 05EH
CTRLP EQU 05FH
;
; Mode instruction values
NULL EQU 080H
;
; To generate mode byte, select one from column A
; and one from column B. See your INTEL dealer for optional
; accessories. Add these all together, and spit 'em out.
; Chef's suggestion: DEFAULT EQU STPB1+BITS7+PEN+EP
; [7 bits, 1 stop bit, even parity]
;
; column A
STPB1 EQU 040H ; 1 stop bit
STPB15 EQU 080H ; 1 1/2 stop bits
STPB2 EQU 0C0H ; 2 stop bits
; column B
BITS5 EQU 000H ; 5 bits/char
BITS6 EQU 004H ; 6 bits/char
BITS7 EQU 008H ; 7 bits/char
BITS8 EQU 00CH ; 8 bits/char
; optional accessories
EP EQU 020H ; 1=even parity, 0=odd
PEN EQU 010H ; 1=enable parity, 0=disable
; required options
; ---> The only one applicable here is 300 baud!!! <---
X64 EQU 003H ; 64x clock rate [300 baud]
;
; the assumed default value
DEFAULT EQU STPB2+BITS8 ; 8 bits, 2 stops, no parity
; Command instruction values
;
; Select desired functions, then add to get command byte
;
EHM EQU 080H ; 1=enter hunt mode [no effect on async op]
; [same as NULL]
IR EQU 040H ; 1=internal reset
RTS EQU 020H ; 1=set RTS to 0, enable transmitter
ER EQU 010H ; 1=reset error conditions
SBRK EQU 008H ; 1=send break [TXD goes "low"]
RXE EQU 004H ; 1=receive enable
TXE EQU 001H ; 1=transmit enable
DTR EQU 002H ; set DTR to 0, seize phone line
;
; Note this important stuff |
; V
; 1: If DTR ever gets set to 0, [SZ or preset goes low] then
; modem goes to originate mode.
; 2: Once line is seized, DTR is set to 1, ^SZ is low, so
; 7474 has preset=H, data=L,.html clear=H. In this condition,
; toggling clock [RTS or ^TXE] will change to answer mode
;
; So what?
;
; With phone hung up, modem is in originate mode. To seize line,
; set DTR and RTS to 1 [this drops ^SZ]. This grabs phone line
; and enables carrier.
; To switch to answer mode, set RTS to 0 then back to 1.
;
; STATUS BITS
;
TXRDY EQU 0 ; indicates transmitter empty
RXRDY EQU 1 ; indicates valid character ready
TXMT EQU 2 ; indicates buffer empty
P_ERR EQU 3 ; set when parity error detected
OE EQU 4 ; set on overrun error
FE EQU 5 ; set on framing error
BD EQU 6 ; set when break detected
DSR EQU 7 ; indicated carrier detect
CD EQU DSR
;
; data areas
C_DATA DEFB NULL ; current 8251 command
;
; global subroutine names
;
GLOBAL DELAY,DIAL,SEIZE,ANSMOD
GLOBAL HANGUP,CD_STAT,U_STAT
GLOBAL CHR_IN,CHR_OUT,M_INIT
GLOBAL SET_UART
;
;***************************************************************************
; SUBROUTINES
;***************************************************************************
;
; Wait 10 msec
DELAY:
PUSH AF ; [3 uSEC]
PUSH BC ; [3]
PUSH DE ; [3]
PUSH HL ; [3]
LD HL,0 ; [2.5]
LD DE,0 ; [2.5]
LD BC,1590
; with all the pushes and pops, we've used about 32 uSEC.
; we need a total of 2,000 LDIRs less 7
; BUT this is off a bit, so we have to go about 18% faster
LDIR
POP HL ; [3]
POP DE ; [3]
POP BC ; [3]
POP AF ; [3]
RET
;
; *************************************
; DIAL DIGIT
; ENTRY: A=ASCII DIGIT 0-9
; EXIT: NONE
DIAL:
PUSH AF
PUSH BC
PUSH DE
PUSH HL
;thaT
CP 'P'
JR Z,PAUSE
CP 'p'
JR Z,PAUSE
CP ',' ;Comma=pause
JR Z,PAUSE
CP '9'+1
JR NC,BAD_DGT ;if character >= ':' then we lose
CP '0'
JR C,BAD_DGT ;if char < '0' then we lose
JR NZ,CHAR_OK
; an ASCII 0 means 10 pulses, so start with '9'+1
LD A,'9'+1
CHAR_OK:
SUB '0'
LD B,A ;number of pulses is now in B
;
PLSE_LP:
; All dialing is in originate mode. We assume that the line was
; already seized.
;
; unseize line for 18/29 of the 100 ms pulse time [60 ms]
LD A,RXE+TXE+RTS
OUT (CTRLP),A ;PICK UP
PUSH BC
LD B,6
PLP1:
CALL DELAY
DJNZ PLP1
POP BC
; seize line for 11/29 of the 100 ms pulse time [40 ms]
LD A,RXE+TXE+RTS+DTR
OUT (CTRLP),A ;PICK UP
PUSH BC
LD B,4
PLP2:
CALL DELAY
DJNZ PLP2
POP BC
;
; next pulse
DJNZ PLSE_LP
LD (C_DATA),A ;SAVE LAST VALUE
;
; delay between digits
PAUSE:
LD B,80 ;800 ms
PLP3:
CALL DELAY
DJNZ PLP3
BAD_DGT:
POP HL
POP DE
POP BC
POP AF
RET
; ***************************
; SEIZE LINE
; ENTRY: A=0 FOR ORIGINATE MODE
; A-0FFH FOR ANSWER MODE
; EXIT: CARRIER IS ENABLED
; REGS A & C GET TRASHED
SEIZE:
LD C,A ; SAVE
CALL HANGUP
LD A,RXE+TXE+RTS+DTR
LD (C_DATA),A ; SAVE LAST COMMAND
OUT (CTRLP),A ; PICK UP
LD A,C
OR A
RET Z ; ALL DONE
; *****************
; ANSWER MODE
; SWITCHES MODEM DIRECTLY TO ANSWER MODE
; Assumes modem off-hook
; EXIT: REG A TRASHED
ANSMOD:
; ONE FULL PULSE OF RTS LINE
LD A,RXE+TXE+DTR
OUT (CTRLP),A
LD A,RXE+TXE+RTS+DTR
LD (C_DATA),A ; SAVE LAST COMMAND
OUT (CTRLP),A
RET
; **********************
; HANGUP
; HANGS UP PHONE. TRASHES REG A
;
HANGUP:
LD A,RXE+TXE+RTS
LD (C_DATA),A ; SAVE LAST COMMAND
OUT (CTRLP),A ; HANG UP PHONE AND SWITCH TO ORIGINATE MODE
RET
; **********************
; CARRIER_STATUS
; READS STATUS FROM UART AND MODEM CHIP
; ENTRY:
; EXIT: NZ=CARRIER DETECT
; Z=NO CARRIER
CD_STAT:
IN A,(CTRLP)
BIT DSR,A
RET
; **********************
; UART_STATUS
; CHECKS UART FOR ERRORS AND/OR DATA
; ENTRY:
; EXIT: NC=NO ERRORS
; C=DATA ERROR
; NZ=CHARACTER PRESENT
; Z=NO CHARACTER
U_STAT:
IN A,(CTRLP)
OR A
JR URT_CMN
URT_ERR:
SCF
URT_CMN:
BIT RXRDY,A
RET
; ************************
; CHARACTER_IN
; ENTRY:
; EXIT: A=CHARACTER FROM MODEM
; NC=NO ERROR
; C=DATA ERROR
CHR_IN:
CALL U_STAT
JR Z,CHR_IN ;WAIT FOR CHARACTER
IN A,(DATAP)
OR A
RET
CHR_ERR:
LD A,(C_DATA)
OR ER ;clear for errors
OUT (CTRLP),A
XOR ER ;disable error reset
OUT (CTRLP),A
LD A,0
RET
; *********************
; CHARACTER_OUT
; ENTRY: A=CHARACTER TO TRANSMIT
; EXIT: NONE
CHR_OUT:
PUSH AF
; WAIT UNTIL TRANSMITTER CLEAR
CHR_L1:
IN A,(CTRLP)
BIT TXMT,A
JR Z,CHR_L1
; DUMP THE SUCKER OUT
POP AF
OUT (DATAP),A
RET
; *************************
; MODEM_INIT
; PRESETS MODEM TO KNOWN INITIAL STATE
M_INIT:
LD A,NULL
LD (C_DATA),A ; fool it into hanging up
LD A,DEFAULT ; desired default value
; *************************
; SET_UART
; SETS UART TO DESIRED STOP BITS, PARITY, ETC
; ENTRY: A=stop bits + bits/char + parity
; EXIT: NONE
SET_UART:
OR X64 ; clock rate is always 64x
PUSH AF
LD A,080H
OUT (CTRLP),A
OUT (CTRLP),A ; get the 8251's attention
LD A,040H
OUT (CTRLP),A
POP AF
OUT (CTRLP),A ; dump the init value out
LD A,(C_DATA)
OUT (CTRLP),A
RET